package net.vsame.v;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.servlet.http.HttpServletRequest;

import net.vsame.v.annotation.VSame;

public class VSameHelper {
	
	private static Invocable jsFunction = null;
	private static ScriptEngine engine = null;
	
	static {
		resetJsInvocable();
	}
	
	/**
	 * 重新设置JS执行接口
	 */
	private static void resetFun(){
		if (engine instanceof Invocable) {
			jsFunction = (Invocable) engine;
		}else{
			throw new RuntimeException("not suppont!");
		}
	}
	
	/**
	 * 重新初始化</br>
	 * 注意：执行完该方法后扩展的脚本全部失效，需依次再执行evel方法
	 */
	public static void resetJsInvocable() {
		ScriptEngineManager manager = new ScriptEngineManager();
		engine  = manager.getEngineByName("JavaScript");

		Reader vsameReader = new InputStreamReader(VSameHelper.class.getResourceAsStream("/vSameJava.js"));
		Reader regexReader = new InputStreamReader(VSameHelper.class.getResourceAsStream("/vSameRegex.js"));
		try {
			engine.eval(vsameReader);
			engine.eval(regexReader);
		}catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			try {
				vsameReader.close();
				regexReader.close();
			} catch (IOException e) {
			}
		}
		resetFun();
	}
	
	/**
	 * 增加扩展校验脚本
	 * @param script
	 */
	public static void eval(String script){
		try {
			engine.eval(script);
		} catch (ScriptException e) {
			throw new RuntimeException(e);
		}
		resetFun();
	}

	/**
	 * @param map 数据map，通常可由request直接获得
	 * @param methodRoles 方法上的规则(注解)
	 * @param clazzRoles 类上的规则(注解)
	 * @return
	 */
	public static Map<String, String> v(Map<String, String[]> map, String[] methodRules, String[] clazzRules){
		Map<String, String> errors = new LinkedHashMap<String, String>();
		try {
			jsFunction.invokeFunction("init", map, errors, methodRules, clazzRules);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return errors;
	}
	
	private static String toJson(String[] arrays){
		if(arrays == null || arrays.length == 0){
			return "[]";
		}
		StringBuffer sb = new StringBuffer("[");
		for(String str : arrays){
			sb.append("\"").append(str.replace("\"", "\\\"")).append("\",");
		}
		sb.deleteCharAt(sb.length()-1).append("]");
		return sb.toString();
	}
	
	/**
	 * 校验数据</br>
	 * 如果参数中包含 ...vsame...auto... 且其值为 ...vsame...auto... 返回校验方法 上 和类上的参数</br>
	 * 反之则为校验数据
	 * @param request
	 * @param method
	 * @return null表示在Method及其类上没有声明VSame注解</br>
	 * 返回为map为错误信息，若map.empty()==true 表示校验通过
	 */
	public static Map<String, String> v(HttpServletRequest request, Method method){
		VSame methodVSame = method.getAnnotation(VSame.class);
		VSame clazzVSame = method.getDeclaringClass().getAnnotation(VSame.class);
		String[] methodRules = new String[]{}, clazzRules = new String[]{};
		if(methodVSame != null){
			methodRules = methodVSame.value();
		}
		if(clazzVSame != null){
			clazzRules = clazzVSame.value();
		}
		if(methodRules.length==0 && clazzRules.length==0){
			return null;//没有规则
		}
		
		if("...vsame...auto...".equals(request.getParameter("...vsame...auto..."))){
			//这是获取后台校验
			Map<String, String> retMap = new LinkedHashMap<String, String>();
			retMap.put("methodRules", toJson(methodRules));
			retMap.put("clazzVSame", toJson(clazzRules));
			return retMap;
		}
		
		@SuppressWarnings("unchecked")
		Map<String, String[]> map = request.getParameterMap();
		return v(map, methodRules, clazzRules);
	}

}
